package com.youxin.foundation.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

/**
 * Class工具类
 * @author yingde.cao
 *
 */
public class ClassUtils {
	/**
	 * 动态初始化类
	 * @param cls 类
	 * @param paramsValue 参数列表LinkedHashMap
	 * @return T
	 */
	@SuppressWarnings("unchecked")
	public static <T> T instance(Class<?> cls,LinkedHashMap<Class<?>, Object> paramsValue) {
		try {
			Class<?>[] clzes=paramsValue.keySet().toArray(new Class<?>[]{});
			Object[] values=paramsValue.values().toArray(new Object[]{});			
			Constructor<?> c = cls.getConstructor(clzes);			
			return (T)c.newInstance(values);
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * 动态初始化类,不带参数
	 * @param cls 类
	 * @return T
	 */
	@SuppressWarnings("unchecked")
	public static <T>  T instance(Class<?> cls)
	{
		try {
			Objenesis objenesis = new ObjenesisStd();
			return (T)objenesis.newInstance(cls);
		} catch (Exception e) {
			return null;
		}		
	}
	
	/**
	 * 获取当前类型所支持的泛型类的泛型类的实际类型
	 * @param cls
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static<T> T getClassGenericFirst(Class<?> cls,int index)
	{
		return (T)((ParameterizedType)cls.getGenericSuperclass())  
                .getActualTypeArguments()[index];  
	}
	
	/**
	 * 获取当前类型所支持的泛型类的泛型类的实际类型
	 * @param cls
	 * @return
	 */
	public static<T> T getClassGenericFirst(Class<?> cls)
	{
		return getClassGenericFirst(cls, 0);
	}
	/**
	 * 代理执行方法
	 * @param t
	 * @param proxyCls
	 * @return
	 */
	public static <T> T proxy(T t,Class<?> proxyCls)
	{
		Class<?> cls=t.getClass();
		LinkedHashMap<Class<?>, Object> linkedHashMap=new LinkedHashMap<>(1);
		linkedHashMap.put(cls, t);
		Object proxyObject=instance(proxyCls, linkedHashMap);
		@SuppressWarnings("unchecked")
		T result = (T)Proxy.newProxyInstance(t.getClass().getClassLoader(), 
			     new Class[]{cls}, 
			     (InvocationHandler)proxyObject);
		return result;
	}
	
	public static Object findPropertyMethod(Object object, Class<?> cls, String[] properties, int index)
			 {
		try {
			Method[] methods = cls.getMethods();
			String propertyName = "get" + properties[index];
			for (Method method : methods) {
				if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
					Object result = method.invoke(object);
					if ((index + 1) == properties.length) {
						return result;
					}
					if(result==null)
						return null;
					Class<?> returnTypeCls = method.getReturnType();
					return findPropertyMethod(result, returnTypeCls, properties, index + 1);
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}		
		return null;
	}
	
	public static Object findPropertyMethod(Object object, Class<?> cls, String propertyName) {
		try {
			Method[] methods = cls.getMethods();
			propertyName = "get" + propertyName;
			for (Method method : methods) {
				if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
					Object result = method.invoke(object);
					return result;					
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}		
		return null;
	}
	
}
